import { nanoid } from 'nanoid'
var _ = require('lodash')
import { getGraphFile } from '@/api/draw.js'
import GraphUtil from '@/utils/graph-utils/graphUtil'
import EventUtil from '@/utils/graph-utils/eventUtil'
import HeaderUtil from '@/utils/graph-utils/headerUtil'
import ConstantUtil from '@/utils/graph-utils/constantUtil'

export default {
  // 重新加载graph
  reloadGraph(component, graph) {
    // 清空当前画布
    graph.clearCells()

    // 从store中获取当前图形文件
    const graphFile = component.$store.state.graphModule.currentGraphFile

    // 加载新的图形文件
    const fileJson = GraphUtil.getLocalstorageItem(graphFile.id)
    if (!fileJson) {
      getGraphFile(graphFile.id).then(response => {
        const file = response.data
        if (file && file.jsonContent && file.jsonContent.content) {
          var newContent = JSON.parse(file.jsonContent.content)
          graph.fromJSON(newContent)
        }
      })
    } else {
      var newContent = JSON.parse(fileJson)
      graph.fromJSON(newContent)
    }

    this.resizeGraph(graph)
  },

  resizeGraph(graph) {
    const width = document.body.offsetWidth - 623
    const height = document.body.offsetHeight - 120 - 20
    graph.resize(width, height)
    graph.resizeGraph(width, height)
  },

  // 为graph添加事件响应
  applyGraphEvents(graph, component) {
    if (!graph || !component) {
      return
    }

    graph.history.on('change', () => {
      component.$store.commit('setRedoUndoState', {
        canRedo: graph.history.canRedo(),
        canUndo: graph.history.canUndo()
      })
    })

    // 有时没有处理blank:click事件，追加一个blank:mousedown事件
    graph.on('blank:mousedown', ({ e }) => {
      component.$store.commit('setOperateNode', undefined)
    })

    // graph.on('node:selected', ({ cell, node, options }) => {
    //   component.$store.commit('setOperateNode', node)
    //   component.$store.commit('setGraphSelectedState')

    //   changePortsVisible(false)
    //   // 取消高亮当前元素
    //   this.unhighlighterNode(node)
    // })
    graph.on('cell:selected', ({ cell }) => {
      component.$store.commit('setOperateNode', cell)
      component.$store.commit('setGraphSelectedState')

      changePortsVisible(false)
      // 取消高亮当前元素
      this.unhighlighterNode(cell)
    })
    graph.on('cell:unselected', () => {
      component.$store.commit('setGraphSelectedState')
    })

    graph.on('edge:added', ({ edge, index, options }) => {
      // edge.setRouter('manhattan')
      edge.setAttrs({
        line: {
          sourceMarker: '',
          targetMarker: '',
          style: 'fill:none;stroke:#7c68fc;stroke-width:4;'
        }
      })
      edge.setData({
        flagId: nanoid(10),
        metaType: ConstantUtil.Metatype_Line,
        metaName: ConstantUtil.Metaname_Line
      })
      EventUtil.addJunctionInfo(graph, edge)
    })

    graph.on('edge:connected', ({ edge, isNew, previousCell, currentCell }) => {
      EventUtil.addJunctionInfo(graph, edge)
    })

    graph.on('edge:removed', ({ edge, index, options }) => {
      EventUtil.removeJunctionInfo(graph, edge)
    })

    graph.on('cell:contextmenu', ({ cell, e }) => {
      component.contextMenuNode = cell
      component.menuVisible = false
      component.menuVisible = true
      var menu = document.querySelector('#menu')
      component.styleMenu(menu)
    })

    // graph.on('cell:change:*', ({ cell, node, key, current, previous, options }) => {
    //   if (key === 'tools') {
    //     return
    //   }
    //   console.log('graph cell changed', key, options)
    // })

    const changePortsVisible = (visible) => {
      const ports = document.getElementById('graphContainer').querySelectorAll('.x6-port-body')
      for (let i = 0, len = ports.length; i < len; i = i + 1) {
        ports[i].style.visibility = visible ? 'visible' : 'hidden'
      }
    }

    graph.on('node:mouseenter', ({ e, node, view }) => {
      changePortsVisible(true)
      // 高亮当前元素
      this.highlighterNode(node)
    })

    graph.on('node:mouseleave', ({ e, node, view }) => {
      changePortsVisible(false)
      // 取消高亮当前元素
      this.unhighlighterNode(node)
    })

    graph.on('edge:mouseenter', ({ cell }) => {
      // cell.addTools([{
      //   name: 'segments',
      //   args: {
      //     precision: 100,
      //     threshold: 10
      //   }
      // }, {
      //   name: 'button-remove',
      //   args: { distance: 20 }
      // }],
      // 'onhover' // 工具集名称，可省略
      // )
      this.highlighterNode(cell)
    })

    graph.on('edge:mouseleave', ({ cell }) => {
      // if (cell.hasTools('onhover')) {
      //   cell.removeTools('onhover')
      // }
      this.unhighlighterNode(cell)
    })

    graph.on('node:added', ({ node, index, options }) => {
      this.createMeasureGroupNode(graph, node)
    })

    graph.on('node:move', ({ e, x, y, node, view }) => {
      if (node.hasParent()) {
        this.previousPosition = node.position()
        this.relativePositions = []
        const parent = node.getParent()
        const childrens = parent.getChildren()
        for (const children of childrens) {
          const position = children.position({
            relative: true
          })
          this.relativePositions.push(position)
        }
      }
    })
    graph.on('node:moving', ({ e, x, y, node, view }) => {
      if (node.hasParent()) {
        const nodePosition = node.position()
        const diffX = nodePosition.x - this.previousPosition.x
        const diffY = nodePosition.y - this.previousPosition.y
        this.previousPosition = node.position()
        const parent = node.getParent()
        const parentPosition = parent.position()
        parent.position(parentPosition.x + diffX, parentPosition.y + diffY)
        this.handleChildPosition(parent)
      }
    })
    graph.on('node:moved', ({ e, x, y, node, view }) => {
      if (node.hasParent()) {
        this.previousPosition = null

        const parent = node.getParent()
        this.handleChildPosition(parent)
      }
    })

    graph.bindKey(['delete', 'backspace'], (event) => {
      var cells = graph.getSelectedCells()
      if (_.isEmpty(cells)) {
        return
      }
      component.$confirm('确认要删除所选择的节点吗?', '删除确认').then(response => {
        cells.forEach((cell) => {
          graph.removeNode(cell)
        })
      }).catch(() => {})
    })

    graph.bindKey('ctrl + a', (event) => {
      event.preventDefault()
      HeaderUtil.handleSelectAll(graph)
    })

    graph.bindKey('ctrl + f', () => {
      var cells = graph.getSelectedCells()

      if (cells.length) {
        cells.forEach((cell) => {
          cell.toFront()
        })
      }
      return false
    })

    graph.bindKey('ctrl+b', () => {
      var cells = graph.getSelectedCells()

      if (cells.length) {
        cells.forEach((cell) => {
          cell.toBack()
        })
      }
      return false
    })

    graph.bindKey(['ctrl + left', 'ctrl + right', 'ctrl + up', 'ctrl + down'], (event, key) => {
      var cells = graph.getSelectedCells()
      cells.forEach((cell) => {
        const position = cell.getPosition()
        key === 'ctrl+left' ? position.x -= 1 : ''
        key === 'ctrl+right' ? position.x += 1 : ''
        key === 'ctrl+up' ? position.y -= 1 : ''
        key === 'ctrl+down' ? position.y += 1 : ''
        cell.setPosition(position.x, position.y)
      })
    })

    graph.bindKey('ctrl + n', (event) => {
      component.$store.commit('newGraphFile')
    })

    graph.bindKey('ctrl + o', (event) => {
      component.$store.commit('openGraphFile')
    })

    graph.bindKey('ctrl + s', (event) => {
      HeaderUtil.handleSave(component, graph, false)
    })

    graph.bindKey('ctrl + shift + s', (event) => {
      HeaderUtil.handleSave(component, graph, true)
    })

    graph.bindKey('ctrl + c', (event) => {
      HeaderUtil.handleCopy(graph)
    })

    graph.bindKey('ctrl + x', (event) => {
      HeaderUtil.handleCut(graph)
    })

    graph.bindKey('ctrl + v', (event) => {
      HeaderUtil.handlePaste(graph)
    })

    graph.bindKey('ctrl + z', (event) => {
      HeaderUtil.handleUndo(graph)
    })

    graph.bindKey('ctrl + y', (event) => {
      HeaderUtil.handleRedo(graph)
    })
  },

  // 处理节点移动事件中子节点的位置
  handleChildPosition(parentNode) {
    const childrens = parentNode.getChildren()
    for (let index = 0; index < childrens.length; index++) {
      const position = this.relativePositions[index]
      childrens[index].position(position.x, position.y, {
        relative: true
      })
    }
  },

  // 高亮节点
  highlighterNode(node) {
    if (node && !node.hasTools('highlight')) {
      node.addTools([{
        name: 'boundary',
        args: {
          padding: 5,
          attrs: {
            fill: '#FF0000',
            stroke: '#FF0000',
            'stroke-width': 1,
            'fill-opacity': 0.2
          }
        }
      }], 'highlight')
    }
  },

  // 取消高亮节点
  unhighlighterNode(node) {
    if (node && node.hasTools('highlight')) {
      node.removeTools('highlight')
    }
  },

  // 是否为量测类型节点
  isMeasureNode(node) {
    return node.data && node.data.rows
  },

  // 获取字符串的宽度和高度
  getStringMetricSize(str) {
    const canvasDiv = document.getElementById('canvasDiv')
    const context = canvasDiv.getContext('2d')
    context.font = '12pt serif'
    const size = context.measureText(str)
    return {
      width: size.width,
      height: size.height
    }
  },

  // 创建量测节点
  createMeasureGroupNode(graph, node) {
    // 当添加量测节点时，删除当前节点，并添加一个Group节点
    if (this.isMeasureNode(node) && node.data.rows.length > 0) {
      const position = node.position()
      const rows = node.data.rows
      let parentNode = null
      rows.forEach((row, rowIndex) => {
        let x = position.x
        const y = position.y + rowIndex * 16
        if (row.length === 0) {
          return
        }

        row.forEach((column) => {
          const { width } = this.getStringMetricSize(column.text)
          const newNode = graph.addNode({
            shape: 'simpleText',
            x: x,
            y: y,
            width: width,
            height: 20,
            attrs: {
              body: column
            },
            data: {
              metaType: ConstantUtil.Metatype_Measure,
              metaName: ConstantUtil.Metatype_Measure,
              flagId: nanoid(10)
            }
          })
          x = position.x + Math.ceil(width) + 10

          if (parentNode == null) {
            parentNode = newNode
          } else {
            parentNode.addChild(newNode)
          }
        })
      })

      // 移除旧的量测节点
      graph.removeNode(node)
    }
  }
}
